#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Constants.h"

using namespace llvm;


//这个Pass首先遍历函数的基本块，并对每个基本块中的指令进行遍历。然后，如果遇到一个二进制运算符指令（如加、减、乘等），
//并且这个指令的两个操作数都是常量整数，那么它就会将这两个整数相加、相减或相乘，并将结果替换为这个指令的使用（调用此指令的指令）。
//最后，如果有任何替换发生，函数将返回“true”，表示发生了更改，否则返回“false”，表示没有进行更改。
//需要注意的是，这个Pass只是一个简单的示例，它只优化了整数常量的二进制运算符
namespace {

    class ConstantFolding : public FunctionPass {
    public:
        static char ID;
        ConstantFolding() : FunctionPass(ID) {}

        bool runOnFunction(Function &F) override {
            bool Changed = false;
            for (auto &BB : F) {
                for (auto &I : BB) {
                    if (auto *BinOp = dyn_cast<BinaryOperator>(&I)) {
                        auto *LHS = dyn_cast<ConstantInt>(BinOp->getOperand(0));
                        auto *RHS = dyn_cast<ConstantInt>(BinOp->getOperand(1));
                        if (LHS && RHS) {
                            int64_t LHSVal = LHS->getSExtValue();
                            int64_t RHSVal = RHS->getSExtValue();
                            Constant *NewConst = nullptr;
                            switch (BinOp->getOpcode()) {
                                case Instruction::Add:
                                    NewConst = ConstantInt::get(BinOp->getType(), LHSVal + RHSVal);
                                    break;
                                case Instruction::Sub:
                                    NewConst = ConstantInt::get(BinOp->getType(), LHSVal - RHSVal);
                                    break;
                                case Instruction::Mul:
                                    NewConst = ConstantInt::get(BinOp->getType(), LHSVal * RHSVal);
                                    break;
                                default:
                                    break;
                            }
                            if (NewConst) {
                                BinOp->replaceAllUsesWith(NewConst);
                                Changed = true;
                            }
                        }
                    }
                }
            }
            return Changed;
        }
    };

} // namespace

char ConstantFolding::ID = 0;
static RegisterPass<ConstantFolding> X("constant-folding", "Constant Folding Pass");
